// Logitech.cpp
/**
 *  @brief 监听Logitech Wireless Gamepad F710手柄事件
 */
#include <iostream>
#include <fstream>
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <sys/stat.h>
#include <dirent.h>
#include <sstream>

/**
 * @brief 游戏手柄管理类
 * 
 * 该类负责查找、连接和管理Logitech游戏手柄设备，
 * 提供设备连接状态查询和文件描述符获取功能。
 */
class GamepadManager {
private:
    std::string device_path;  ///< 设备路径
    int fd;                   ///< 设备文件描述符
    bool connected;           ///< 连接状态标志
    
public:
    /**
     * @brief 构造函数
     * 
     * 初始化游戏手柄管理器，设置文件描述符为-1，连接状态为false
     */
    GamepadManager() : fd(-1), connected(false) {}
    
    /**
     * @brief 析构函数
     * 
     * 自动关闭已打开的设备文件描述符，释放资源
     */
    ~GamepadManager() {
        if (fd != -1) {
            close(fd);
        }
    }
    
    /**
     * @brief 查找Logitech游戏手柄设备
     * 
     * 遍历/dev/input目录下的所有event设备文件，通过ioctl获取设备名称，
     * 查找包含"Logitech"字样的设备
     * 
     * @return std::string 找到的设备完整路径，未找到则返回空字符串
     */
    std::string findLogitechDevice() {
        // 遍历 /dev/input 目录下的所有 event 文件
        DIR* dir = opendir("/dev/input");
        if (!dir) {
            std::cerr << "无法打开 /dev/input 目录\n";
            return "";
        }
        
        struct dirent* entry;
        while ((entry = readdir(dir)) != nullptr) {
            if (strncmp(entry->d_name, "event", 5) == 0) {
                std::string full_path = "/dev/input/" + std::string(entry->d_name);
                
                // 尝试读取设备信息
                int temp_fd = open(full_path.c_str(), O_RDONLY);
                if (temp_fd == -1) continue;
                
                // 获取设备名称
                char name[256] = "Unknown";
                if (ioctl(temp_fd, EVIOCGNAME(sizeof(name)), name) < 0) {
                    close(temp_fd);
                    continue;
                }
                std::cout << "设备名称: " << name << "\n";
                // 检查是否包含 Logitech 字样
                if (strstr(name, "Logitech")) {
                    close(temp_fd);
                    closedir(dir);
                    return full_path;
                }
                
                close(temp_fd);
            }
        }
        
        closedir(dir);
        return "";
    }
    
    /**
     * @brief 连接游戏手柄设备
     * 
     * 查找并连接Logitech游戏手柄设备，如果已经连接则直接返回true，
     * 否则尝试查找设备并建立连接
     * 
     * @return bool 连接成功返回true，失败返回false
     */
    bool connect() {
        if (connected && fd != -1) {
            return true;
        }
        
        device_path = findLogitechDevice();
        if (device_path.empty()) {
            return false;
        }
        
        fd = open(device_path.c_str(), O_RDONLY);
        if (fd == -1) {
            std::cerr << "无法打开设备: " << device_path << "\n";
            return false;
        }
        
        connected = true;
        std::cout << "✅ 成功连接游戏手柄: " << device_path << "\n";
        return true;
    }
    
    /**
     * @brief 断开游戏手柄连接
     * 
     * 关闭已打开的设备文件描述符，并重置连接状态
     */
    void disconnect() {
        if (fd != -1) {
            close(fd);
            fd = -1;
        }
        connected = false;
        std::cout << "🎮 游戏手柄已断开连接\n";
    }
    
    /**
     * @brief 查询连接状态
     * 
     * @return bool 已连接返回true，未连接返回false
     */
    bool isConnected() {
        return connected;
    }
    
    /**
     * @brief 获取文件描述符
     * 
     * @return int 设备文件描述符
     */
    int getFd() {
        return fd;
    }
};

/**
 * @brief 主函数，用于监听和处理Logitech游戏手柄事件
 * 
 * 该函数初始化游戏手柄管理器，持续检测手柄连接状态，
 * 并在手柄连接时读取和解析输入事件（按键和摇杆）。
 * 支持的按键包括A、B、X、Y按钮，LB、RB肩键，Start和Back按钮。
 * 支持的摇杆和触发器包括左右摇杆、LT/RT触发器和方向键。
 * 
 */
int main() {
    GamepadManager gamepad;
    
    std::cout << "🎮 开始监听Logitech游戏手柄事件...\n";
    std::cout << "请插入Logitech游戏手柄\n";
    
    input_event event;
    
    while (true) {
        // 检查并处理手柄连接状态
        if (!gamepad.isConnected()) {
            if (gamepad.connect()) {
                std::cout << "🎮 开始监听手柄事件... 按 Ctrl+C 退出。\n\n";
            } else {
                usleep(500000); // 等待500ms再检查
                continue;
            }
        }
        
        ssize_t bytes = read(gamepad.getFd(), &event, sizeof(event));
        if (bytes == sizeof(event)) {
            // 解析按键事件和摇杆事件
            if (event.type == EV_KEY) {
                std::string key_name;
                switch (event.code) {
                    case BTN_SOUTH:   key_name = "A Button";     break;
                    case BTN_EAST:    key_name = "B Button";     break;
                    case BTN_NORTH:   key_name = "X Button";     break;
                    case BTN_WEST:    key_name = "Y Button";     break;
                    case BTN_TL:      key_name = "LB";           break;
                    case BTN_TR:      key_name = "RB";           break;
                    case BTN_START:   key_name = "Start";        break;
                    case BTN_SELECT:  key_name = "Back";         break;
                    default:          key_name = "Unknown Key";  break;
                }
                std::cout << "[KEY]  " << key_name 
                          << (event.value ? " 按下" : " 释放") << "\n";
                
                // 🔧 在这里添加控制逻辑，例如：
                // if (event.code == BTN_SOUTH && event.value == 1) car.forward();
            }
            else if (event.type == EV_ABS) {
                std::string axis_name;
                switch (event.code) {
                    case ABS_X:     axis_name = "Left Stick X";   break;
                    case ABS_Y:     axis_name = "Left Stick Y";   break;
                    case ABS_RX:    axis_name = "Right Stick X";  break;
                    case ABS_RY:    axis_name = "Right Stick Y";  break;
                    case ABS_Z:     axis_name = "LT Trigger";     break;
                    case ABS_RZ:    axis_name = "RT Trigger";     break;
                    case ABS_HAT0X: axis_name = "D-Pad X";        break;
                    case ABS_HAT0Y: axis_name = "D-Pad Y";        break;
                    default:        axis_name = "Axis";           break;
                }
                std::cout << "[AXIS] " << axis_name << " = " << event.value << "\n";

                // 🔧 映射到小车速度控制，例如：
                // left_speed  = map_stick(event.value, ABS_Y); // 左摇杆上下
                // steering    = map_stick(event.value, ABS_X); // 左摇杆左右
            }
            // EV_SYN 是同步事件，通常可忽略
        }
        else {
            // 处理设备断开连接的情况
            gamepad.disconnect();
            std::cout << "等待重新连接手柄...\n";
        }
    }
    
    return 0;
}